/*
 * This file is part of the Try! Engine project.
 *
 * Copyright 2010-2011 Emanuele Bertoldi. All rights reserved.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * You should have received a copy of the modified BSD License along with this
 * program. If not, see <http://www.opensource.org/licenses/bsd-license.php>
 */

#include "selectiontool.h"
#include <projectmodellist.h>
#include <scenetransformable.h>
#include <cameranode.h>
#include <QtGui/QMouseEvent>

using namespace Try;

SelectionTool::SelectionTool(QObject* parent)
    :   Tool(tr("Selection"), "../../data/icons/select.png", parent),
        m_selectionBox(0)
{
    QObject::connect(this, SIGNAL(activationChanged()), this, SLOT(onActivationChanged()));
}

SelectionTool::~SelectionTool()
{
    delete m_selectionBox;
}

bool SelectionTool::eventFilter(QObject* watched, QEvent* evt)
{
    if (watched && watched == this->targetView() && this->isActive())
    {
        this->updateSelectionBox();

        switch (evt->type())
        {
            case QEvent::MouseButtonPress:
            {
                QMouseEvent* mouse_evt = static_cast<QMouseEvent*>(evt);
                Project* project = ProjectModelList::instance()->projectAt(0);

                if (project && mouse_evt && mouse_evt->buttons() == Qt::LeftButton)
                {
                    if (!mouse_evt->modifiers().testFlag(Qt::ControlModifier))
                        project->deselectAllObjects();

                    View3d* view3d = this->targetView();

                    if (view3d && view3d->activeCamera())
                    {
                        QPoint mpos = mouse_evt->pos();

                        // Normalize coordinates.
                        float x = mpos.x() / (float)view3d->width();
                        float y = (view3d->height() - mpos.y()) / (float)view3d->height();

                        SceneNode* node = view3d->activeCamera()->pickNode(x, y);

                        if (node)
                        {
                            StringList names;

                            foreach (SceneTransformable* t, SceneTransformable::query(node))
                            {
                                Object* owner = t->owner();
                                project->selectObject(owner);
                                names.push_back(owner->name());
                            }

                            QMainWindow* main = qobject_cast<QMainWindow*>(view3d->parentWidget());
                            if (main)
                            {
                                QString msg = tr("Selected: %1").arg(String::join(names, ", ").c_str());

                                main->statusBar()->showMessage(msg);
                            }
                        }
                    }
                }
            }
            break;

            default:
                break;
        }
    }

    return false;
}

void SelectionTool::onActivationChanged()
{
    if (this->isActive() && !m_selectionBox)
    {
        m_selectionBox = new Box(Vector3::Zero, Vector3::Zero, Colors::White);

        QObject::connect(ProjectModelList::instance(), SIGNAL(projectSelectionChanged(Project*)), this, SLOT(onProjectSelectionChanged(Project*)));
    }

    this->updateSelectionBox();
}

void SelectionTool::onProjectSelectionChanged(Project* project)
{
    this->updateSelectionBox();
}

void SelectionTool::updateSelectionBox()
{
    if (m_selectionBox)
    {
        ObjectList selection;
        Project* project = ProjectModelList::instance()->projectAt(0);

        if (project)
        {
            selection = project->selectedObjects();
            AxisAlignedBoundingBox selection_aabb;

            foreach (Object* object, selection)
            {
                SceneTransformable* transform = object->property<SceneTransformable>();

                if (transform)
                    selection_aabb.join(transform->worldAABB());
            }

            m_selectionBox->m_center = selection_aabb.center();
            m_selectionBox->m_size = selection_aabb.size();
        }

        m_selectionBox->setVisible(project && selection.size() > 0);
    }
}
